package com.mathcat.mobile.android.net;

import java.net.UnknownHostException;

import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.StatusLine;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;

import android.util.Log;

import com.mathcat.mobile.android.util.Task;

/**
 * HttpTransaction.
 * 
 * @author Mathcat
 * @version 1.0.1, 2011.03.14
 */
public class HttpTransaction implements Task {

	// Canceling.
	// Error Handling.
	// 		4xx, 5xx Response; Timeout; Permission denied; Network IO Exception; 
	// Redirecting.
	// 		Auto redirecting ?
	// Caching.
	// Proxy.
	// Check CMCC.
	
	private static final String LOG_TAG = HttpTransaction.class.getSimpleName();
	
	final static int STATUS_INITIALIZED = 1;
	final static int STATUS_WAITING = 2;
	final static int STATUS_EXECUTING = 3;
	final static int STATUS_COMPLETED = 4;
	final static int STATUS_FAILED = 5;
	final static int STATUS_CANCELED = 6;
	
	volatile int status;
	
	HttpRequestBase request;
	
	HttpCaller caller;
	
	HttpLoader loader;
	
	private HttpClient httpClient;
	
	HttpTransaction(HttpRequestBase request, HttpCaller caller, HttpLoader loader) {
		this.request = request;
		this.caller = caller;
		this.loader = loader;
		
		this.status = STATUS_INITIALIZED;
	}
	
	@Override
	public void execute() {
		
		if (this.status == STATUS_CANCELED)
			return;
		
		init();
		
		this.status = STATUS_EXECUTING;
		
		try {
			
			HttpRequestBase request = this.request;
			
			HttpResponse response = httpClient.execute(request);
			
			if (this.status == STATUS_CANCELED)
				return;
			
			Log.d(LOG_TAG, "Connecting to " + request.getURI());
			StatusLine statusLine = response.getStatusLine();
			int statusCode = statusLine.getStatusCode();
			
			switch (statusCode) {
				// 2xx Success.
				case HttpStatus.SC_OK:
					this.status = STATUS_COMPLETED;
					Log.d(LOG_TAG, "HTTP request succeed; request uri: " + request.getURI());
					if (this.caller != null) {
						this.caller.onCompelete(response);
					}
					break;
				// 3xx Redirecting.
				// 		Auto Redirecting?
				case HttpStatus.SC_SEE_OTHER:
				case HttpStatus.SC_MOVED_TEMPORARILY:
				case HttpStatus.SC_MOVED_PERMANENTLY:
					break;
				// 4xx Client Failed.
				// 5xx Server Failed.
				default:
					break;
			}
			
		} catch (UnknownHostException e) {
			Log.e(LOG_TAG, "HTTP request failed; request uri: " + request.getURI() + ", error message: " + e.getMessage());
			if (this.caller != null) {
				caller.onFailed(HttpCaller.ERROR_CODE_UNKNOWN_HOST);
			}
		} catch (java.net.SocketTimeoutException e) {
			Log.e(LOG_TAG, "HTTP request failed; request uri: " + request.getURI() + ", error message: " + e.getMessage());
			if (this.caller != null) {
				caller.onFailed(HttpCaller.ERROR_CODE_TIMEOUT);
			}
		} catch (org.apache.http.conn.ConnectTimeoutException e) {
			Log.e(LOG_TAG, "HTTP request failed; request uri: " + request.getURI() + ", error message: " + e.getMessage());
			if (this.caller != null) {
				caller.onFailed(HttpCaller.ERROR_CODE_TIMEOUT);
			}
		} catch (Exception e) {
			Log.e(LOG_TAG, "HTTP request failed; request uri: " + request.getURI() + ", error message: " + e.getMessage());
			e.printStackTrace();
			if (this.caller != null) {
				caller.onFailed(HttpCaller.ERROR_CODE_UNKNOWN);
			}
		}
	}

	@Override
	public void cancel() {
		if (this.status == STATUS_EXECUTING) {
			request.abort();
		}
		
		Log.d(LOG_TAG, "HTTP request canceled; request uri: " + request.getURI());
		this.status = STATUS_CANCELED;
		
		if (this.caller != null) {
			this.caller.onFailed(HttpCaller.ERROR_CODE_CANCELED);
		}
	}

	private void init() {
		HttpParams params = new BasicHttpParams();

		HttpConnectionParams.setConnectionTimeout(params, loader.timeout);
		HttpConnectionParams.setSoTimeout(params, loader.timeout);
		HttpConnectionParams.setSocketBufferSize(params, 8912);
		
		httpClient = new DefaultHttpClient(params);
	}
}
